package com.xyh.transaction.handler;

import com.meilisearch.sdk.exceptions.MeilisearchException;
import com.xyh.transaction.exception.*;
import com.xyh.transaction.response.ResponseCode;
import com.xyh.transaction.response.ResponseResult;
import com.xyh.transaction.utils.EmailUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.firewall.RequestRejectedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MaxUploadSizeExceededException;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @Autowired
    private EmailUtil emailUtil;

    @Value("${email.enabled}")
    private boolean emailEnabled;

    /**
     * 获取异常消息或默认消息
     */
    private String getMessageOrDefault(String message) {
        return message != null ? message : "未提供详细错误消息";
    }

    /**
     * 统一处理日志记录
     */
    private void logExceptionWithRequest(Exception e, HttpServletRequest request, String defaultMessage) {
        log.error("{}: {}", defaultMessage, getMessageOrDefault(e.getMessage()), e);
        if (request != null) {
            log.error("请求URL: {}", request.getRequestURL());
            log.error("请求URI: {}", request.getRequestURI());
        }
    }

    /**
     * 异常处理的核心逻辑
     */
    private ResponseResult<String> handleException(Exception e, HttpStatus status, String defaultMessage, boolean sendEmail, HttpServletRequest request) {
        logExceptionWithRequest(e, request, defaultMessage);
        // 发送异常邮件
        if (sendEmail && emailEnabled) {
            emailUtil.sendExceptionToAdmin(e);
        } else if (sendEmail) {
            log.warn("邮件功能未启用，未发送异常邮件。");
        }
        return ResponseResult.failure(status.value(), defaultMessage + getMessageOrDefault(e.getMessage()));
    }

    @ResponseBody
    @ExceptionHandler({
            FileSizeLimitExceededException.class,
            MaxUploadSizeExceededException.class
    })
    public ResponseResult<String> handleFileSizeLimitExceeded(Exception e, HttpServletRequest request) {
        return handleException(e, HttpStatus.BAD_REQUEST, "上传的文件大小超过了限制，请重新上传。", false, request);
    }

    @ResponseBody
    @ExceptionHandler(LoginException.class)
    public ResponseResult<String> handleLoginException(LoginException e, HttpServletRequest request) {
        return handleException(e, HttpStatus.UNAUTHORIZED, "登录异常：", false, request);
    }

    @ResponseBody
    @ExceptionHandler(DuplicateUsernameException.class)
    public ResponseResult<String> handleDuplicateUsernameException(DuplicateUsernameException e, HttpServletRequest request) {
        return handleException(e, HttpStatus.CONFLICT, "用户名重复异常", false, request);
    }

    @ResponseBody
    @ExceptionHandler(ExcelExportException.class)
    public ResponseResult<String> handleExcelExportException(ExcelExportException e, HttpServletRequest request) {
        return handleException(e, HttpStatus.BAD_REQUEST, "Excel 导出异常", false, request);
    }

    @ResponseBody
    @ExceptionHandler(ImageOperationException.class)
    public ResponseResult<String> handleImageOperationException(ImageOperationException e, HttpServletRequest request) {
        return handleException(e, HttpStatus.INTERNAL_SERVER_ERROR, "图片处理异常", false, request);
    }

    @ResponseBody
    @ExceptionHandler({
            ReadExcelException.class,
            UpdateException.class,
            DeleteException.class,
            InsertException.class
    })
    public ResponseResult<String> handleDataOperationException(Exception e, HttpServletRequest request) {
        return handleException(e, HttpStatus.INTERNAL_SERVER_ERROR, "数据操作异常：", false, request);
    }

    @ResponseBody
    @ExceptionHandler(AccessDeniedException.class)
    public ResponseResult<String> handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) {
        return handleException(e, HttpStatus.FORBIDDEN, "SpringSecurity 权限校验异常", false, request);
    }

    @ResponseBody
    @ExceptionHandler(AuthenticationException.class)
    public ResponseResult<String> handleAuthenticationException(AuthenticationException e, HttpServletRequest request) {
        return handleException(e, HttpStatus.UNAUTHORIZED, "SpringSecurity 登录认证异常", false, request);
    }

    @ResponseBody
    @ExceptionHandler(RequestRejectedException.class)
    public ResponseResult<String> handleRequestRejectedException(RequestRejectedException e, HttpServletRequest request) {
        return handleException(e, HttpStatus.BAD_REQUEST, "请求路径错误，请联系管理员！", false, request);
    }

    @ResponseBody
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseResult<String> handleUserNotFoundException(UserNotFoundException e) {
        return ResponseResult.failure(ResponseCode.NOT_FOUND_USER);
    }

    @ResponseBody
    @ExceptionHandler(MeilisearchException.class)
    public ResponseResult<String> handleMeilisearchException(MeilisearchException e, HttpServletRequest request) {
        return handleException(e, HttpStatus.INTERNAL_SERVER_ERROR, "Meilisearch 发生异常：", true, request);
    }

    @ResponseBody
    @ExceptionHandler(ClientAbortException.class)
    public ResponseResult<String> handleClientAbortException(ClientAbortException e, HttpServletRequest request) {
        // 使用 408 状态码表示客户端中断 TODO: 待确认是否合理，是否有其他处理方案
        log.warn("客户端中断异常：{}", e.getMessage());
        return null;
    }


    @ResponseBody
    @ExceptionHandler(Exception.class)
    public ResponseResult<String> handleGenericException(Exception e, HttpServletRequest request) {
        return handleException(e, HttpStatus.INTERNAL_SERVER_ERROR, "系统发生异常：", true, request);
    }
}
